package org.dentalcard.ui.calendar;

import org.dentalcard.entity.DecUser;
import org.dentalcard.entity.Shift;
import org.dentalcard.entity.Visit;
import org.dentalcard.entity.WorkDay;
import org.dentalcard.service.impl.ScheduleDaoImpl;
import org.dentalcard.ui.api.DecInternalFrame;
import org.dentalcard.ui.i18n.I18nManager;
import org.dentalcard.ui.main.MainFrameBuilder;
import org.dentalcard.ui.multispantable.AttributiveCellTableModel;
import org.dentalcard.ui.multispantable.CellSpan;
import org.dentalcard.ui.multispantable.MultiSpanCellTable;
import org.dentalcard.ui.tools.DateTextField;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * @user: Vladimir Chernishov
 * @date: 20.12.11
 * @time: 20:36
 */
public class DayCalendarScr extends DecInternalFrame {

    private final JPanel main;
    private MultiSpanCellTable table;
    private AttributiveCellTableModel ml;
    private JTable weekTable;
    private DateTextField dateField = new DateTextField();
    private List<WorkDay> workDays = new ArrayList<WorkDay>();
    private int currentDayIndex = 0;
    private JTable dayFreeTime;
    private Date firstDayOfWeek;
    private JTable visitTable;
    private DateFormat timeFormat = new SimpleDateFormat("HH:mm");
    
    
    public DayCalendarScr() {
        super(I18nManager.getRes("working.day"));
        main = new JPanel(new GridBagLayout());
        this.getContentPane().add(new JScrollPane(main, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS), BorderLayout.CENTER);
        init();
    }

    private void init() {
        initTable();

        initMenuBar();

        int rowN = 0;
        dateField.setEnabled(false);
        dateField.setValue(new Date());
        reloadTable(new Date());
        dateField.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                reloadTable(((DateTextField) e.getSource()).getDate());
            }
        });
        main.add(dateField, new GridBagConstraints(0, rowN++, 1 ,1, 0, 0, GridBagConstraints.FIRST_LINE_START,
                GridBagConstraints.NONE, new Insets(5, 5, 0, 5), 0, 0));

        main.add(this.getWeekTable().getTableHeader(), new GridBagConstraints(0, rowN++, 2 ,1, 1, 0, GridBagConstraints.FIRST_LINE_START,
                GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0));
        main.add(this.getWeekTable(), new GridBagConstraints(0, rowN++, 2 ,1, 1, 0, GridBagConstraints.FIRST_LINE_START,
                GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0));
        
        main.add(this.getDayFreeTime().getTableHeader(), new GridBagConstraints(0, rowN++, 2 ,1, 1, 0, GridBagConstraints.FIRST_LINE_START,
                GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0));
        main.add(this.getDayFreeTime(), new GridBagConstraints(0, rowN++, 2 ,1, 1, 0, GridBagConstraints.FIRST_LINE_START,
                GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0));

        main.add(this.getVisitTable().getTableHeader(), new GridBagConstraints(0, rowN++, 2 ,1, 1, 0, GridBagConstraints.FIRST_LINE_START,
                GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0));
        main.add(this.getVisitTable(), new GridBagConstraints(0, rowN++, 2 ,1, 1, 0, GridBagConstraints.FIRST_LINE_START,
                GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0));

        main.add(table.getTableHeader(), new GridBagConstraints(0, rowN++, 2 ,1, 1, 0, GridBagConstraints.FIRST_LINE_START,
                GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0));
        main.add(table, new GridBagConstraints(0, rowN++, 1 ,2, 1, 0, GridBagConstraints.FIRST_LINE_START,
                GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 5), 0, 0));

    }

    private JTable getVisitTable() {
        if(visitTable == null){
            visitTable = new JTable();
            initVisitTable();
        }
        return visitTable;
    }

    private void initVisitTable() {
        WorkDay workDay = workDays.get(currentDayIndex);
        if(workDay != null) {
            DefaultTableModel visitModel = new DefaultTableModel(new Object[]{"Time", "Description"}, 0);
            List<Visit> visitList = workDay.getVisits();
            if(!visitList.isEmpty()) {
                for (int i = 0; i < visitList.size(); i++) {
                    Visit visit = visitList.get(i);
                    visitModel.addRow(new Object[]{timeFormat.format(visit.getTime()), visit.getDescription()});
                }
                visitTable.setModel(visitModel);
                visitTable.getTableHeader().setVisible(true);
                visitTable.setVisible(true);
                return;
            }
        }
        visitTable.setVisible(false);
        visitTable.getTableHeader().setVisible(false);

    }

    private void initMenuBar() {
        JMenuBar menu = new JMenuBar();
        JButton addPatientVisit = new JButton(I18nManager.getRes("button.add.patient.visit"));
        addPatientVisit.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                WorkDay workDay = workDays.get(currentDayIndex);
                if(workDay != null){
                    AddPatientVisitPopup popup = new AddPatientVisitPopup(MainFrameBuilder.getMainFrame(),
                            getCurrentDate(), workDay);
                    popup.setVisible(true);
                } else {
                    JOptionPane.showInternalMessageDialog(DayCalendarScr.this, "Today is day off.");
                }
            }
        });

        menu.add(addPatientVisit);
        rootPane.setJMenuBar(menu);
    }

    private void reloadTable(Date date) {
        ScheduleDaoImpl scheduleDao = new ScheduleDaoImpl();
        WorkDay workDay = scheduleDao.getShift(MainFrameBuilder.getUser(), date);

        if(workDay == null){
            return;
        }
        Shift shift = workDay.getShift();
        for(int i = 0, time = shift.getFromTime(); (i*3) < ml.getRowCount(); i++, time++){
            int row = i * 3;
            if(time < shift.getTillTime()){
                ml.setValueAt(String.valueOf(time), row, 0);
            }else {
                ml.setValueAt(I18nManager.getRes("free.time"), row, 0);
            }
        }
    }

    private void initTable() {
        int rows = 24 * 3;
        ml = new AttributiveCellTableModel(rows, 2);
        final CellSpan cellAtt = (CellSpan) ml.getCellAttribute();
        table = new MultiSpanCellTable(ml);
        table.getColumnModel().getColumn(0).setWidth(20);
        table.getColumnModel().getColumn(1).setWidth(400);

        for (int ii = 0; (ii * 3) < rows; ii++) {
            int row = ii * 3;
            ml.setValueAt(String.valueOf(ii), row, 0);
            cellAtt.combine(new int[]{row, row + 1, row + 2}, new int[]{0});
        }
    }

    public JTable getWeekTable() {
        if(weekTable == null){
            DefaultTableModel model = new DefaultTableModel(0, 7);
            weekTable = new JTable(model);
            model.setColumnIdentifiers(new Object[]{I18nManager.getRes("monday"), I18nManager.getRes("tuesday"),
                    I18nManager.getRes("wednesday"), I18nManager.getRes("thursday"), I18nManager.getRes("friday"),
                    I18nManager.getRes("saturday"), I18nManager.getRes("sunday")});
            model.addRow(new Object[]{"", "", "", "", "", "", ""});
            model.addRow(new Object[]{"", "", "", "", "", "", ""});

            Calendar calendar = GregorianCalendar.getInstance();
            calendar.setTime(getCurrentDate());
            calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY );
            firstDayOfWeek = calendar.getTime();
            ScheduleDaoImpl dao = new ScheduleDaoImpl();
            for(int i =0; i < 7; i++){
                WorkDay workDay = dao.getWorkDay(getCurrentUser(), calendar.getTime());
                if(workDay != null){
                    workDays.add(workDay);
                    model.setValueAt(workDay.getShift(), 0, i);
                    List<Visit> visitList = workDay.getVisits();
                    model.setValueAt(I18nManager.getRes("day.calendar.visits", visitList.size()), 1, i);
                } else {
                    workDays.add(null);
                    model.setValueAt(Shift.DAY_OFF, 0, i);
                    model.setValueAt(I18nManager.getRes("day.calendar.visits", 0), 1, i);
                }
                calendar.add(Calendar.DAY_OF_YEAR, 1);
            }
            weekTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            weekTable.setColumnSelectionAllowed(true);
            weekTable.setRowSelectionAllowed(false);
            weekTable.getTableHeader().setReorderingAllowed(false);

            Calendar date = GregorianCalendar.getInstance();
            if(date.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY){
//                model.setValueAt(I18nManager.getRes("today"), 0, 6);
                currentDayIndex = 6;
            } else {
                currentDayIndex = date.get(Calendar.DAY_OF_WEEK) - 2;
//                model.setValueAt(I18nManager.getRes("today"), 0, selectedColumn);
            }
            weekTable.setColumnSelectionInterval(currentDayIndex, currentDayIndex);
            ListSelectionListener sslectionListener = new ListSelectionListener() {
                @Override
                public void valueChanged(ListSelectionEvent e) {
                    if (currentDayIndex != weekTable.getSelectedColumn()) {
                        currentDayIndex = weekTable.getSelectedColumn();
                        onDateChange();
                        main.updateUI();
                    }
                }
            };
            weekTable.getSelectionModel().addListSelectionListener(sslectionListener);
            weekTable.getColumnModel().getSelectionModel().addListSelectionListener(sslectionListener);
        }
        return weekTable;
    }

    private void onDateChange() {
        dateField.setValue(calculateCurrentDate());
        initDayFreeTable();
        initVisitTable();
    }

    private Date calculateCurrentDate() {
        WorkDay workDay = workDays.get(currentDayIndex);
        if (workDay != null) {
            return workDay.getDay();
        } else if (currentDayIndex == 0) {
            return firstDayOfWeek;
        } else {
            Calendar date = GregorianCalendar.getInstance();
            date.setTime(firstDayOfWeek);
            date.add(Calendar.DAY_OF_YEAR, currentDayIndex);
            return date.getTime();
        }
    }

    private DecUser getCurrentUser() {
        return MainFrameBuilder.getUser();
    }

    public Date getCurrentDate() {
        return dateField.getDate();
    }

    public JTable getDayFreeTime() {
        if(dayFreeTime == null){
            dayFreeTime = new JTable();
            initDayFreeTable();
        }
        
        return dayFreeTime;
    }

    private void initDayFreeTable() {
        WorkDay workDay = workDays.get(currentDayIndex);
        if(workDay != null) {
            int workingHours = workDay.getShift().getTillTime() - workDay.getShift().getFromTime();
            int columnCount = workingHours * 3;
            String[] columns = new String[columnCount];
            for(int i = 0; i < columnCount; i++){
                int minutes = i % 3;
                int hour = i/3 + workDay.getShift().getFromTime();
                if(minutes  == 0){
                    columns[i] = hour + ":00";
                } else if(minutes  == 1){
                    columns[i] = hour + ":20";
                } else if(minutes  == 2){
                    columns[i] = hour + ":40";
                }
            }
            DefaultTableModel model = new DefaultTableModel(columns, 2);
            model.setValueAt(workDay.getDay(), 0, 0);
            dayFreeTime.setModel(model);
           
        } else {
            dayFreeTime.setModel(new DefaultTableModel());
        }
    }
}
